#include "crypt.h"

int init_module(MCRYPT *td, char *algo, char *mode){
  /* Ouverture du module */
  *td = mcrypt_module_open(algo, NULL, mode, NULL);
  if (*td == MCRYPT_FAILED) {  
    fprintf(stderr, "Initialisation impossible...\n");
  }

  return mcrypt_enc_get_key_size(*td);
}

int init_crypt_module(MCRYPT *td, char *algo, char *mode, char** key, char* password, char** iv){

  /* Ouverture du module */
  *td = mcrypt_module_open(algo, NULL, mode, NULL);
  if (*td == MCRYPT_FAILED) {  
    fprintf(stderr, "Initialisation impossible...\n");
  }

  int keysize = mcrypt_enc_get_key_size(*td);
  int ivsize = mcrypt_enc_get_iv_size(*td);
  char key_tmp[keysize];
  char iv_tmp[ivsize];

  *key = (char*) malloc(sizeof(char)*keysize);
  *iv = (char*) malloc(sizeof(char)*ivsize);
 
  //printf("\nMaximum size of the key: %d bits\n", keysize*8);
  //printf("Maximum size of the IV: %d bits\n\n", ivsize*8);

  /* Génération de la clé et de l'IV */
  key_generator(key_tmp, keysize, password);

  strcpy(*key, key_tmp);
  strcpy(*iv, key_tmp);
  printf("IV: %s\n\n", *iv);

  /* Initialisation du cryptage*/
  if(mcrypt_generic_init(*td, *key, keysize, *iv) < 0)
    fprintf(stderr, "Erreur lors de l'initialisation du cryptage...\n");

  return keysize;
}

void key_generator(char* key, int keysize, char* password){
  KEYGEN * keygen = (KEYGEN *) malloc(sizeof(KEYGEN));
  keygen->hash_algorithm[0] = MHASH_MD5;

  /* Génération de la clé à partir du password */
  if(mhash_keygen_ext(KEYGEN_MCRYPT, *keygen, key, keysize, password, strlen(password)) < 0)
    fprintf(stderr, "Erreur lors de la génération de la clé...\n");
  free(keygen);
  //printf("\nClé généré: %s\n\n", key);
}


char* crypt_block(MCRYPT* td, char * plaintext, int* tailleCrypt){
  /* Récupère la taille des blocs */
  int blocksize = mcrypt_enc_get_block_size(*td);
  int taillePlaintext = strlen(plaintext);
  int taille_malloc = (taillePlaintext / blocksize + 1) * blocksize;
  char * message = (char*) malloc(taille_malloc);

  /* On renvoi la taille de la chaine cryptée */
  *tailleCrypt = taille_malloc;

  /* On copie le message */
  memcpy(message, plaintext, taillePlaintext+1);
  //printf("Réception du payload pour cryptage: %s \n", message);

  /* Encryptage du message */
  int r = mcrypt_generic(*td, message, taille_malloc);
  if(r != 0){
    fprintf(stderr, "Erreur lors de l'encryptage...\n");
    mcrypt_perror(r);
  }
  
  //printf("\nMessage crypté avec succès...\n\n");

  return message;
}

char* decrypt_block(MCRYPT* td, char * cyphertext, int tailleCypher){
  /* Récupère la taille des blocs */
  int blocksize = mcrypt_enc_get_block_size(*td);
  char * message = (char*) malloc(tailleCypher * sizeof(char));
  
  /* On copie le message */
  memcpy(message, cyphertext, tailleCypher+1);
  
  /* Décryptage du message */
  int r = mdecrypt_generic(*td, message, tailleCypher);
  if(r != 0){
    fprintf(stderr, "Erreur lors du décryptage...\n");
    mcrypt_perror(r);
  }
  //printf("\nMessage Décrypté: %s \n\n", message);

  return message;
}

unsigned char* hash(hashid type, char* content, int* size){

  MHASH td;
  unsigned char* hash; /* pour MD5 */
  *size = mhash_get_block_size(type);

  hash = (unsigned char*) malloc(sizeof(unsigned char)*mhash_get_block_size(type));

  //printf("Contenu à Hasher: %s\n\n", content);

  /* Initialisation du hashage */
  td = mhash_init(type);

  if (td == MHASH_FAILED)
    fprintf(stderr, "Erreur lors de l'initialisation du hashage...\n");
  
  /* Met à jour le contexte */
  mhash(td, content, strlen(content));

  /* Insère le résultat dans hash */
  mhash_deinit(td, hash);

  /* Affiche le hash */
  //printf("Hashage terminé avec succès: ");
  //afficheHash(MHASH_MD5, hash);

  return hash;
}

void close_module(MCRYPT* td){
  mcrypt_generic_deinit(*td);
  mcrypt_module_close(*td);
}

void afficheHash(int mode,unsigned char * hash){
  int i;
  
  for (i = 0; i < mhash_get_block_size(mode); i++) {
    printf("%.2x", hash[i]);
  }
  printf("\n\n");
}
